import json
import requests
import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
                             QWidget, QPushButton, QTextEdit, QLabel, QMessageBox,
                             QProgressBar, QSplitter)
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QFont


class DataFetcher(QThread):
    """数据获取线程"""
    finished = pyqtSignal(bool, str)
    progress = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.headers = {
            "accept": "application/json, text/plain, */*",
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,ar;q=0.7",
            "cache-control": "no-cache",
            "origin": "https://xuangutong.com.cn",
            "pragma": "no-cache",
            "priority": "u=1, i",
            "referer": "https://xuangutong.com.cn/dingpan",
            "sec-ch-ua": "\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Microsoft Edge\";v=\"138\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "cross-site",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
        }
        self.url = "https://flash-api.xuangubao.com.cn/api/pool/detail"
        self.params = {"pool_name": "limit_up"}

    def is_st_stock(self, name):
        """判断是否为ST股票"""
        if not name:
            return False
        name = name.upper()
        return name.startswith('ST') or name.startswith('*ST') or 'ST' in name

    def run(self):
        try:
            self.progress.emit("正在获取数据...")
            response = requests.get(self.url, headers=self.headers, params=self.params)
            response.raise_for_status()

            self.progress.emit("正在保存原始数据...")
            # 保存原始JSON数据
            with open("demo.json", "w", encoding="utf-8") as f:
                f.write(response.text)

            self.progress.emit("正在解析数据...")
            # 解析JSON数据
            data = response.json()

            # 添加数据检查
            if not data or "data" not in data or not data["data"]:
                self.finished.emit(False, "API返回数据为空或格式错误")
                return

            # 第一遍遍历：统计每个板块的涨停数量（排除ST股票）
            plate_count = {}
            for item in data["data"]:
                if not item:  # 检查item是否为None
                    continue

                # 检查是否为ST股票 - 修改字段名
                stock_name = item.get("stock_chi_name", "") if item else ""
                if self.is_st_stock(stock_name):
                    continue

                surge_reason = item.get("surge_reason") if item else None
                if not surge_reason:
                    continue

                related_plates = surge_reason.get("related_plates", []) if surge_reason else []
                for plate in related_plates:
                    if not plate:  # 检查plate是否为None
                        continue

                    plate_name = plate.get("plate_name", "") if plate else ""
                    if plate_name and plate_name != "ST股":  # 排除ST股板块
                        plate_count[plate_name] = plate_count.get(plate_name, 0) + 1

            # 创建板块索引（按涨停数量排序，数量多的排在前面，"其他"排在最后）
            plate_names = list(plate_count.keys())
            other_plates = [name for name in plate_names if name == "其他"]
            normal_plates = [name for name in plate_names if name != "其他"]

            # 按涨停数量排序，数量多的排在前面
            normal_plates.sort(key=lambda x: plate_count[x], reverse=True)

            # 最终顺序：正常板块（按数量排序） + "其他"
            plate_index = normal_plates + other_plates
            plate_to_index = {plate: i + 1 for i, plate in enumerate(plate_index)}

            # 准备数据
            limit_up_numbers = []  # 涨停数字
            limit_up_reasons = []  # 涨停理由

            # 第二遍遍历：处理股票数据（排除ST股票）
            for item in data["data"]:
                if not item:  # 检查item是否为None
                    continue

                # 检查是否为ST股票 - 修改字段名
                stock_name = item.get("stock_chi_name", "") if item else ""
                if self.is_st_stock(stock_name):
                    continue

                # 处理股代码格式转换
                raw_symbol = item.get("symbol", "") if item else ""
                if not raw_symbol:
                    continue

                if raw_symbol.endswith(".SZ"):
                    symbol = "SZ" + raw_symbol.split('.')[0]
                elif raw_symbol.endswith(".SS"):
                    symbol = "SH" + raw_symbol.split('.')[0]
                else:
                    symbol = raw_symbol

                # 收集所有板块理由
                surge_reason = item.get("surge_reason") if item else None
                if not surge_reason:
                    continue

                related_plates = surge_reason.get("related_plates", []) if surge_reason else []

                plate_indices = []
                plate_names_list = []

                for plate in related_plates:
                    if not plate:  # 检查plate是否为None
                        continue

                    plate_name = plate.get("plate_name", "") if plate else ""
                    if plate_name and plate_name != "ST股":
                        plate_names_list.append(plate_name)
                        if plate_name in plate_to_index:
                            plate_indices.append(plate_to_index[plate_name])

                # 检查是否有板块索引
                if not plate_indices:
                    continue

                # 按索引排序
                plate_indices.sort()

                # 将索引用小数点连接成字符串
                if len(plate_indices) == 1:
                    indices_str = str(plate_indices[0])
                elif len(plate_indices) == 2:
                    indices_str = f"{plate_indices[0]}.{plate_indices[1]}"
                else:
                    # 三个或以上索引：第一个数字.后面的数字连接
                    indices_str = str(plate_indices[0]) + "." + "".join(map(str, plate_indices[1:]))

                # 保存数据
                limit_up_numbers.append((symbol, indices_str))
                # 涨停理由使用所有板块名称，用空格分隔
                reasons_str = ' '.join(plate_names_list)
                limit_up_reasons.append((symbol, reasons_str))

            self.progress.emit("正在保存文件...")
            # 保存涨停数字到txt文件 - 使用GBK编码
            with open("涨停数字.txt", "w", encoding="gbk") as f:
                for symbol, indices in limit_up_numbers:
                    f.write(f"{symbol}\t{indices}\n")

            # 保存涨停理由到txt文件 - 使用GBK编码
            with open("涨停理由.txt", "w", encoding="gbk") as f:
                for symbol, reason in limit_up_reasons:
                    f.write(f"{symbol}\t{reason}\n")

            # 保存板块索引到txt文件 - 使用GBK编码
            with open("板块索引.txt", "w", encoding="gbk") as f:
                for i, plate_name in enumerate(plate_index, 1):
                    f.write(f"{i}\t{plate_name}\n")

            success_msg = f"数据获取成功！共处理了 {len(limit_up_numbers)} 只涨停股票（已排除ST股票）"
            self.finished.emit(True, success_msg)

        except requests.exceptions.RequestException as e:
            self.finished.emit(False, f"请求失败：{e}")
        except json.JSONDecodeError as e:
            self.finished.emit(False, f"JSON解析失败：{e}")
        except KeyError as e:
            self.finished.emit(False, f"数据结构错误，缺少字段：{e}")
        except Exception as e:
            self.finished.emit(False, f"发生错误：{e}")


class StockAnalyzer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.data_fetcher = None

    def initUI(self):
        self.setWindowTitle('股票涨停数据分析器')
        self.setGeometry(100, 100, 1200, 800)

        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        # 创建主布局
        main_layout = QVBoxLayout()
        central_widget.setLayout(main_layout)

        # 创建顶部按钮区域
        top_layout = QHBoxLayout()

        # 获取数据按钮
        self.fetch_btn = QPushButton('获取涨停数据')
        self.fetch_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 10px;
                font-size: 14px;
                font-weight: bold;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
        """)
        self.fetch_btn.clicked.connect(self.fetch_data)
        top_layout.addWidget(self.fetch_btn)

        # 添加弹性空间
        top_layout.addStretch()

        main_layout.addLayout(top_layout)

        # 创建中部按钮区域
        middle_layout = QHBoxLayout()

        # 查看按钮
        self.view_numbers_btn = QPushButton('查看涨停数字')
        self.view_reasons_btn = QPushButton('查看涨停理由')
        self.view_plates_btn = QPushButton('查看板块索引')

        # 设置按钮样式
        button_style = """
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 8px 16px;
                font-size: 12px;
                border-radius: 4px;
                margin: 2px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
            QPushButton:pressed {
                background-color: #1565C0;
            }
            QPushButton:disabled {
                background-color: #CCCCCC;
                color: #666666;
            }
        """

        self.view_numbers_btn.setStyleSheet(button_style)
        self.view_reasons_btn.setStyleSheet(button_style)
        self.view_plates_btn.setStyleSheet(button_style)

        # 初始状态禁用查看按钮
        self.view_numbers_btn.setEnabled(False)
        self.view_reasons_btn.setEnabled(False)
        self.view_plates_btn.setEnabled(False)

        # 连接按钮事件
        self.view_numbers_btn.clicked.connect(lambda: self.view_file('涨停数字.txt'))
        self.view_reasons_btn.clicked.connect(lambda: self.view_file('涨停理由.txt'))
        self.view_plates_btn.clicked.connect(lambda: self.view_file('板块索引.txt'))

        middle_layout.addWidget(self.view_numbers_btn)
        middle_layout.addWidget(self.view_reasons_btn)
        middle_layout.addWidget(self.view_plates_btn)
        middle_layout.addStretch()

        main_layout.addLayout(middle_layout)

        # 创建文本显示区域
        self.text_display = QTextEdit()
        self.text_display.setFont(QFont("Courier New", 10))
        self.text_display.setReadOnly(True)
        self.text_display.setStyleSheet("""
            QTextEdit {
                background-color: #f5f5f5;
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 8px;
            }
        """)
        self.text_display.setPlainText("请先获取数据，然后点击查看按钮来查看不同类型的数据...")

        main_layout.addWidget(self.text_display)

        # 创建状态栏
        self.status_label = QLabel('就绪')
        self.status_label.setStyleSheet("""
            QLabel {
                background-color: #f0f0f0;
                border: 1px solid #ccc;
                padding: 5px;
                border-radius: 3px;
            }
        """)
        main_layout.addWidget(self.status_label)

        # 设置窗口居中
        self.center()

    def center(self):
        """窗口居中"""
        screen = QApplication.desktop().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)

    def fetch_data(self):
        """获取数据"""
        self.fetch_btn.setEnabled(False)
        self.fetch_btn.setText('正在获取数据...')

        # 禁用查看按钮
        self.view_numbers_btn.setEnabled(False)
        self.view_reasons_btn.setEnabled(False)
        self.view_plates_btn.setEnabled(False)

        # 创建并启动数据获取线程
        self.data_fetcher = DataFetcher()
        self.data_fetcher.progress.connect(self.update_status)
        self.data_fetcher.finished.connect(self.on_data_fetched)
        self.data_fetcher.start()

    def update_status(self, message):
        """更新状态"""
        self.status_label.setText(message)

    def on_data_fetched(self, success, message):
        """数据获取完成"""
        self.fetch_btn.setEnabled(True)
        self.fetch_btn.setText('获取涨停数据')

        if success:
            self.status_label.setText(message)
            # 启用查看按钮
            self.view_numbers_btn.setEnabled(True)
            self.view_reasons_btn.setEnabled(True)
            self.view_plates_btn.setEnabled(True)

            # 显示成功消息
            QMessageBox.information(self, '成功',
                                    message + '\n\n文件已保存：\n- 涨停数字.txt\n- 涨停理由.txt\n- 板块索引.txt\n- demo.json')

            # 默认显示涨停数字
            self.view_file('涨停数字.txt')
        else:
            self.status_label.setText(f'错误: {message}')
            QMessageBox.critical(self, '错误', message)

    def view_file(self, filename):
        """查看文件内容"""
        try:
            if not os.path.exists(filename):
                QMessageBox.warning(self, '警告', f'文件 {filename} 不存在，请先获取数据')
                return

            # 读取文件时也使用GBK编码
            with open(filename, 'r', encoding='gbk') as f:
                content = f.read()

            # 添加文件标题
            title = f"========== {filename} ==========\n\n"
            self.text_display.setPlainText(title + content)

            # 更新状态
            self.status_label.setText(f'正在查看: {filename}')

            # 移动光标到顶部
            cursor = self.text_display.textCursor()
            cursor.movePosition(cursor.Start)
            self.text_display.setTextCursor(cursor)

        except Exception as e:
            QMessageBox.critical(self, '错误', f'读取文件失败: {e}')
            self.status_label.setText(f'读取文件失败: {e}')


def main():
    app = QApplication(sys.argv)
    app.setStyle('Fusion')  # 使用Fusion样式

    # 设置应用程序样式
    app.setStyleSheet("""
        QMainWindow {
            background-color: #f0f0f0;
        }
        QWidget {
            font-family: "微软雅黑", "Arial", sans-serif;
        }
    """)

    analyzer = StockAnalyzer()
    analyzer.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()